//
// Created by tcj on 2021/12/2.
//
#ifndef __SYLAR_LOG_H__
#define  __SYLAR_LOG_H__

#include <memory>
#include <list>
#include <fstream>
#include <vector>
#include <map>
#include "iostream"
#include "string"
#include "sstream"
#include "singleton.h"
#include "util.h"
#include "thread.h"

#define SYLAR_LOG_LEVEL(logger,level) \
    if(logger->getlevel() <=level)    \
        sylar::LogEventWarp(sylar::LogEvent::ptr(new sylar::LogEvent(logger,level, \
                __FILE__,__LINE__,0,sylar::GetThreadId(), \
            sylar::GetFirberid(),time(0),sylar::Thread::GetName()))).getSS()

#define SYLAR_LOG_DEBUG(logger) SYLAR_LOG_LEVEL(logger,sylar::LogLevel::DEBUG)
#define SYLAR_LOG_INFO(logger) SYLAR_LOG_LEVEL(logger,sylar::LogLevel::INFO)
#define SYLAR_LOG_WARN(logger) SYLAR_LOG_LEVEL(logger,sylar::LogLevel::WARN)
#define SYLAR_LOG_ERROR(logger) SYLAR_LOG_LEVEL(logger,sylar::LogLevel::ERROR)
#define SYLAR_LOG_FATAL(logger) SYLAR_LOG_LEVEL(logger,sylar::LogLevel::FATAL)


#define SYLAR_LOG_FMT_LEVEL(logger,level,fmt,...) \
    if(logger->getlevel() <=level)    \
        sylar::LogEventWarp(sylar::LogEvent::ptr(new sylar::LogEvent(logger,level, \
                __FILE__,__LINE__,0,sylar::GetThreadId(), \
            sylar::GetFirberid(),time(0),sylar::Thread::GetName()))).getEvent()->format(fmt,__VA_ARGS__)

#define SYLAR_LOG_FMT_DEBUG(logger,fmt,...) SYLAR_LOG_FMT_LEVEL(logger,sylar::LogLevel::DEBUG,fmt,__VA_ARGS__)
#define SYLAR_LOG_FMT_INFO(logger,fmt,...) SYLAR_LOG_FMT_LEVEL(logger,sylar::LogLevel::INFO,fmt,__VA_ARGS__)
#define SYLAR_LOG_FMT_WARN(logger,fmt,...) SYLAR_LOG_FMT_LEVEL(logger,sylar::LogLevel::WARN,fmt,__VA_ARGS__)
#define SYLAR_LOG_FMT_ERROR(logger,fmt,...) SYLAR_LOG_FMT_LEVEL(logger,sylar::LogLevel::ERROR,fmt,__VA_ARGS__)
#define SYLAR_LOG_FMT_FATAL(logger,fmt,...) SYLAR_LOG_FMT_LEVEL(logger,sylar::LogLevel::FATAL,fmt,__VA_ARGS__)


//获取主日志器
#define SYLAR_LOG_ROOT() sylar::loggerMar::GetInstance()->getRoot()

#define SYLAR_LOG_NAME(name) sylar::loggerMar::GetInstance()->getLogger(name)

namespace sylar{
    class Logger;

    //日志级别
    class LogLevel{
    public:
        enum Level{
            UNKNOW=0,  //未知
            DEBUG = 1,  //debug时候出来的信息
            INFO = 2,  //信息
            WARN = 3,  //警告
            ERROR = 4,  //出错
            FATAL =5  //致命情况
        };

        static const char* Tostring(LogLevel::Level level);
        static LogLevel::Level Fromstring(const std::string& str);
    };

    //日志事件
    class LogEvent{
    public:
        typedef std::shared_ptr <LogEvent> ptr;
        LogEvent(std::shared_ptr<Logger> logger,LogLevel::Level level,const char* file,
                 int32_t m_line,uint32_t elapse,uint32_t thresd_id,uint32_t fiberid,
                 uint64_t time,const std::string thread_name);

        const char* getFile() const {return m_file;}
        int32_t getLine() const {return m_line;}
        uint32_t getElapse() const {return m_elapse;}
        int32_t getThread() const {return m_threadId;}
        uint32_t getFiberId() const {return m_fiberId;}
        uint64_t getTime() const {return m_time;}
        const std::string& getThreadName() const { return m_threadName;}
        std::string getContent() const {return m_ss.str();}
        std::shared_ptr<Logger> getLogger() const {return m_logger;};
        LogLevel::Level getLevel() const {return m_level;}

        std::stringstream& getSS(){return m_ss;}
        void format(const char* fmt,...);
        void format(const char* fmt, va_list al);
    private:
        const char* m_file = nullptr;   // 文件名
        int32_t m_line=0;               //行号
        uint32_t m_elapse = 0;          //程序启动到现在的毫秒数
        int32_t m_threadId = 0;         //线程id
        uint32_t m_fiberId =0;          //协程id
        uint64_t m_time =0;             //时间戳
        std::string m_content;          //
        std::stringstream m_ss;         //日志内容流
        std::string m_threadName;       //线程名称

        std::shared_ptr<Logger> m_logger;       //日志器
        LogLevel::Level m_level;                //日志等级
    };

    // 日志事件包装器
//    ：日志事件包装器，将日志事件与日志器包装在一起，通过宏定义简化日志模块的使用，当期析构时候，则调用日志器的log方法进行输出；
    class LogEventWarp{
    public:
        LogEventWarp(LogEvent::ptr e);
        ~LogEventWarp();

        LogEvent::ptr getEvent() const { return m_event;}
        std::stringstream&  getSS();
    private:
        LogEvent::ptr m_event;
    };

    //日志格式器
    class LogFormatter{
    public:
        typedef std::shared_ptr<LogFormatter> ptr;
        LogFormatter(const std::string& pattern);
        //日志格式
        std::string format(std::shared_ptr<Logger> logger,LogLevel::Level level,LogEvent::ptr event);
        std::ostream& format(std::ostream& ofs, std::shared_ptr<Logger> logger, LogLevel::Level level, LogEvent::ptr event);
    public:
        class FormatItem{
        public:
            typedef std::shared_ptr<FormatItem> ptr;
            FormatItem(const std::string& fmt=""){}
            virtual ~FormatItem(){}
            virtual void format(std::ostream& os,std::shared_ptr<Logger> logger,LogLevel::Level level,LogEvent::ptr event) = 0;
        };
        void init();

        bool isError() const {return m_error;}
        const std::string getPattern() const {return m_pattern;}
    private:
        std::string m_pattern;
//        存放日志的各个部分
        std::vector<FormatItem::ptr> m_items;
        bool m_error = false;
    };


    //日志输出地
    class LoggAppender{
    friend class Logger;
    public:
        typedef std::shared_ptr<LoggAppender> ptr;
        typedef SpinLock Mutextype;
        virtual ~LoggAppender(){}

        virtual void log(std::shared_ptr<Logger> logger, LogLevel::Level level,LogEvent::ptr event) = 0;
        virtual std::string toYamlString()=0;

        void setFormatter(LogFormatter::ptr val);
        LogFormatter::ptr getFormatter();
        LogLevel::Level getLevel() const{ return m_level;}
        void setLevel(LogLevel::Level val) { m_level = val;}
    protected:
        LogLevel::Level m_level=LogLevel::DEBUG;
        bool m_hasFormatter = false;
        Mutextype m_mutex;
        //输出格式
        LogFormatter::ptr m_formatter;
    };


    //日志器
//    日志器，负责日志输出，提供log方法，若该日志需要输出则调用LogAppender将日志输出，否则抛弃；
//  std::enable_shared_from_this 能让一个对象（假设其名为 t ，且已被一个 std::shared_ptr 对象 pt 管理）
//              安全地生成其他额外的 std::shared_ptr 实例（假设名为 pt1, pt2, ... ） ，它们与 pt 共享对象 t 的所有权。
//       若一个类 T 继承 std::enable_shared_from_this<T> ，则会为该类 T 提供成员函数： shared_from_this 。
//       当 T 类型对象 t 被一个为名为 pt 的 std::shared_ptr<T> 类对象管理时，调用 T::shared_from_this 成员函数，
//       将会返回一个新的 std::shared_ptr<T> 对象，它与 pt 共享 t 的所有权。

    class Logger :public std::enable_shared_from_this<Logger>{
    friend class LoggerManner;
    public:
        typedef std::shared_ptr<Logger> ptr;
        typedef SpinLock Mutextype;

        Logger(const std::string& name="root");

        void log(LogLevel::Level level,LogEvent::ptr event);

        void debug(LogEvent::ptr event);
        void info(LogEvent::ptr event);
        void warn(LogEvent::ptr event);
        void error(LogEvent::ptr event);
        void fatal(LogEvent::ptr event);

        void addAppender(LoggAppender::ptr appender);
        void delAppender(LoggAppender::ptr appender);
        void clearAppenders();
        LogLevel::Level getlevel() const {return m_level;}
        void setlevel(LogLevel::Level val) {m_level = val;}

        const std::string& getName() const {return m_name;}

        void setFormatter(LogFormatter::ptr val);
        void setFormatter(const std::string& val);

        LogFormatter::ptr getFormatter();
        std::string toYamlString();
    private:
        std::string m_name;         //日志名称
        LogLevel::Level m_level;    //日志级别
        Mutextype m_mutex;
        std::list<LoggAppender::ptr> m_Appenders;          //appender集合
        LogFormatter::ptr m_formatter;
        Logger::ptr m_root;
    };




    //输出到控制台的Appender
    class StdoutLogAppender: public LoggAppender{
    public:
        typedef std::shared_ptr<StdoutLogAppender> ptr;
        void log(Logger::ptr logger,LogLevel::Level level,LogEvent::ptr event) override;
        std::string toYamlString() override;
    private:
    };
    //输出到文件的Appender
    class FileLogAppender : public LoggAppender{
    public:
        typedef std::shared_ptr<FileLogAppender> ptr;
        FileLogAppender(const std::string& filename);
        //继承父类Appender的方法
        void log(Logger::ptr logger,LogLevel::Level level,LogEvent::ptr event) override;
        std::string toYamlString() override;

        bool reopen();
    private:
        std::string m_filename;
        std::ofstream m_filestream;
        uint64_t m_lastTime=0;

    };

//    日志管理器
    class LoggerManner{
    public:
        typedef SpinLock Mutextype;
        LoggerManner();
        Logger::ptr getLogger(const std::string& name);

        void init();
        Logger::ptr getRoot() const {return m_root;}
        std::string toYamlString();
    private:
        Mutextype m_mutex;
        std::map<std::string,Logger::ptr> m_logger;
        Logger::ptr m_root;
    };

//日志器的管理类单例模式
    typedef sylar::Singleton<LoggerManner> loggerMar;


}
#endif